<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="author" content="GoJun" />
	
	
	
	<title>Android 与 Flutter 之间通信 ｜ GoJun</title>
	
    
    
    <meta name="description" content="概述 Flutter 与原生之间的通信机制都是通过 Platform Channel 进行传递，如下图所示： 原生 与 Flutter 之间的通信主要有有四种实现方式： 在初始化 Flutter 页面时会传递一个字符串 Route，因此我们就可以通过 Route 从 原生 向 Flutter 端传递自己想要的数据； 通过" />
    

    
    
    <meta name="keywords" content="Hugo, theme, zozo" />
    

	
    
    <link rel="shortcut icon" href="https://gojun.me/images/favicon.ico" />

    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.mecss/normalize.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/animate.css@4.1.0/animate.min.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/zozo.css" />
	<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/highlight.css" />

    
    
</head>

<body>
    <div class="main animate__animated animate__fadeInDown">
        <div class="nav_container animated fadeInDown">
    <div class="site_nav" id="site_nav">
        <ul>
            
            <li>
                <a href="/">Home</a>
            </li>
            
            <li>
                <a href="/posts/">Archive</a>
            </li>
            
            <li>
                <a href="/tags/">Tags</a>
            </li>
            
            <li>
                <a href="/projects/">Projects</a>
            </li>
            
        </ul>
    </div>
    <div class="menu_icon">
        <a id="menu_icon"><i class="ri-menu-line"></i></a>
    </div>
</div>
        <div class="header animated fadeInDown">
    <div class="site_title_container">
        <div class="site_title">
            <h1>
                <a href="https://gojun.me">
                    <span>GoJun</span>
                </a>
            </h1>
        </div>
        <div class="description">
            <p class="sub_title">为向往生活努力奋斗！</p>
            <div class="my_socials">
                
                
                <a href="https://github.com/freelander" title="github" target="_blank"><i class="ri-github-fill"></i></a>
                
                
                <a href="https://gojun.me/index.xml" type="application/rss+xml" title="rss" target="_blank"><i
                        class="ri-rss-fill"></i></a>
            </div>
        </div>
    </div>
</div>
        <div class="content">
            <div class="post_page">
                <div class="post animate__animated animate__fadeInDown">
                    <div class="post_title post_detail_title">
                        <h2><a href='/posts/flutter-channel/'>Android 与 Flutter 之间通信</a></h2>
                        <span class="date">2020.04.02</span>
                    </div>
                    <div class="post_content markdown"><h3 id="概述">概述</h3>
<p>Flutter 与原生之间的通信机制都是通过 Platform Channel 进行传递，如下图所示：</p>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2020/04/flutter_channel_01.png">
<img src="/images/2020/04/flutter_channel_01.png" alt="image"  />
</a>
</div>

</p>
<p>原生 与 Flutter 之间的通信主要有有四种实现方式：</p>
<ol>
<li>在初始化 Flutter 页面时会传递一个字符串 Route，因此我们就可以通过 Route 从 <code>原生</code> 向 <code>Flutter</code> 端传递自己想要的数据；</li>
<li>通过 MethodChannel 来实现，MethodChannel 支持数据双向传递，有返回值。</li>
<li><del>通过 EventChannel 来实现，EventChannel 仅支持数据单向传递，无返回值。</del></li>
<li><del>通过 BasicMessageChannel 来实现，BasicMessageChannel 支持数据双向传递，有返回值。</del></li>
</ol>
<h3 id="flutter-向原生通信">Flutter 向原生通信</h3>
<h4 id="flutter-端">Flutter 端</h4>
<div class="highlight"><pre class="chroma"><code class="language-dart" data-lang="dart">
<span class="kd">class</span> <span class="nc">MethodChannelPage</span> <span class="kd">extends</span> <span class="n">StatefulWidget</span> <span class="p">{</span>
  <span class="err">@</span><span class="n">override</span>
  <span class="n">_MethodChannelPageState</span> <span class="n">createState</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="n">_MethodChannelPageState</span><span class="p">();</span>
<span class="p">}</span>

<span class="kd">class</span> <span class="nc">_MethodChannelPageState</span> <span class="kd">extends</span> <span class="n">State</span><span class="o">&lt;</span><span class="n">MethodChannelPage</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="c1">// 创建通信渠道，通道名称必须唯一，且与原生那边统一
</span><span class="c1"></span>  <span class="n">MethodChannel</span> <span class="n">methodsChannel</span> <span class="o">=</span> <span class="n">MethodChannel</span><span class="p">(</span><span class="s2">&#34;com.chicdeals/methodsChannel&#34;</span><span class="p">);</span>
  <span class="kt">String</span> <span class="n">_langText</span> <span class="o">=</span> <span class="s1">&#39;切换语言&#39;</span><span class="p">;</span>

  <span class="err">@</span><span class="n">override</span>
  <span class="n">Widget</span> <span class="n">build</span><span class="p">(</span><span class="n">BuildContext</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">Scaffold</span> <span class="p">(</span>
      <span class="nl">backgroundColor:</span> <span class="n">Color</span><span class="p">(</span><span class="mh">0xFFFFFFFF</span><span class="p">),</span>
      <span class="nl">body:</span> <span class="n">Align</span><span class="p">(</span>
        <span class="nl">alignment:</span> <span class="n">Alignment</span><span class="p">.</span><span class="n">center</span><span class="p">,</span>
        <span class="nl">child:</span> <span class="n">Container</span><span class="p">(</span>
          <span class="nl">height:</span> <span class="m">44</span><span class="p">,</span>
          <span class="nl">padding:</span> <span class="n">EdgeInsets</span><span class="p">.</span><span class="n">only</span><span class="p">(</span><span class="nl">left:</span> <span class="m">10</span><span class="p">,</span> <span class="nl">right:</span> <span class="m">10</span><span class="p">),</span>
          <span class="nl">alignment:</span> <span class="n">Alignment</span><span class="p">.</span><span class="n">center</span><span class="p">,</span>
          <span class="nl">child:</span> <span class="n">RaisedButton</span><span class="p">(</span>
            <span class="nl">child:</span> <span class="n">Text</span><span class="p">(</span>
              <span class="n">_langText</span><span class="p">,</span>
            <span class="p">),</span>
            <span class="nl">textColor:</span> <span class="n">Colors</span><span class="p">.</span><span class="n">white</span><span class="p">,</span>
            <span class="nl">color:</span> <span class="n">Color</span><span class="p">(</span><span class="mh">0xFF49C9A7</span><span class="p">),</span>
            <span class="nl">onPressed:</span> <span class="n">_sendMethodToNative</span><span class="p">,</span>
          <span class="p">),</span>
        <span class="p">),</span>
      <span class="p">),</span>
    <span class="p">);</span>
  <span class="p">}</span>

  <span class="n">Future</span><span class="o">&lt;</span><span class="kt">void</span><span class="o">&gt;</span> <span class="n">_sendMethodToNative</span><span class="p">()</span> <span class="kd">async</span> <span class="p">{</span>
    <span class="kt">String</span> <span class="n">sendMsg</span> <span class="o">=</span> <span class="s1">&#39;Flutter切换语言&#39;</span><span class="p">;</span>
    <span class="c1">// 向原生发送消息，标识符为 &#39;flutter_change_language&#39;
</span><span class="c1"></span>    <span class="c1">// 原生那边接收到消息，并相应结果回来
</span><span class="c1"></span>    <span class="kt">String</span> <span class="n">result</span> <span class="o">=</span> <span class="kd">await</span> <span class="n">methodsChannel</span><span class="p">.</span><span class="n">invokeMethod</span><span class="p">(</span><span class="s1">&#39;flutter_change_language&#39;</span><span class="p">,</span> <span class="n">sendMsg</span><span class="p">);</span>
    <span class="c1">// 刷新页面按钮文案
</span><span class="c1"></span>    <span class="n">setState</span><span class="p">(()</span> <span class="p">{</span>
      <span class="n">_langText</span> <span class="o">=</span> <span class="n">result</span><span class="p">;</span>
    <span class="p">});</span>
  <span class="p">}</span>
<span class="p">}</span>

</code></pre></div><h4 id="android-端">Android 端</h4>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">class</span> <span class="nc">FlutterDemoActivity</span> <span class="kd">extends</span> <span class="n">AppCompatActivity</span> <span class="o">{</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">TAG_FLUTTER_FRAGMENT</span> <span class="o">=</span> <span class="s">&#34;flutter_fragment&#34;</span><span class="o">;</span>
    <span class="kd">private</span> <span class="n">MaterialButton</span> <span class="n">mBtnChangeLanguage</span><span class="o">;</span>
    <span class="kd">private</span> <span class="n">FlutterFragment</span> <span class="n">mFlutterFragment</span><span class="o">;</span>

    <span class="kd">private</span> <span class="n">MethodChannel</span> <span class="n">mMethodChannel</span><span class="o">;</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="nd">@Nullable</span> <span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">);</span>
        <span class="n">setContentView</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">activiy_flutter_demo</span><span class="o">);</span>
        <span class="n">mBtnChangeLanguage</span> <span class="o">=</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">btn_change_language</span><span class="o">);</span>

        <span class="n">FragmentManager</span> <span class="n">fragmentManager</span> <span class="o">=</span> <span class="n">getSupportFragmentManager</span><span class="o">();</span>

        <span class="n">mFlutterFragment</span> <span class="o">=</span> <span class="o">(</span><span class="n">FlutterFragment</span><span class="o">)</span> <span class="n">fragmentManager</span><span class="o">.</span><span class="na">findFragmentByTag</span><span class="o">(</span><span class="n">TAG_FLUTTER_FRAGMENT</span><span class="o">);</span>

        <span class="c1">// Create and attach a FlutterFragment if one does not exist.
</span><span class="c1"></span>        <span class="k">if</span> <span class="o">(</span><span class="n">mFlutterFragment</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">mFlutterFragment</span> <span class="o">=</span> <span class="n">FlutterFragment</span><span class="o">.</span><span class="na">withNewEngine</span><span class="o">()</span>
                    <span class="o">.</span><span class="na">initialRoute</span><span class="o">(</span><span class="s">&#34;Flutter Demo&#34;</span><span class="o">)</span>
                    <span class="o">.</span><span class="na">build</span><span class="o">();</span>

            <span class="n">fragmentManager</span>
                    <span class="o">.</span><span class="na">beginTransaction</span><span class="o">()</span>
                    <span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">container</span><span class="o">,</span> <span class="n">mFlutterFragment</span><span class="o">,</span> <span class="n">TAG_FLUTTER_FRAGMENT</span><span class="o">)</span>
                    <span class="o">.</span><span class="na">commit</span><span class="o">();</span>
        <span class="o">}</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onPostCreate</span><span class="o">(</span><span class="nd">@Nullable</span> <span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">.</span><span class="na">onPostCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">);</span>
        <span class="c1">// 通道名称需要与 Flutter 模块那边统一，并且唯一
</span><span class="c1"></span>        <span class="n">mMethodChannel</span> <span class="o">=</span> <span class="k">new</span> <span class="n">MethodChannel</span><span class="o">(</span><span class="n">getBinaryMessenger</span><span class="o">(),</span> <span class="s">&#34;com.chicdeals/methodsChannel&#34;</span><span class="o">);</span>
        
        <span class="n">mMethodChannel</span><span class="o">.</span><span class="na">setMethodCallHandler</span><span class="o">(</span><span class="k">new</span> <span class="n">MethodChannel</span><span class="o">.</span><span class="na">MethodCallHandler</span><span class="o">()</span> <span class="o">{</span>
            <span class="nd">@Override</span>
            <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMethodCall</span><span class="o">(</span><span class="nd">@NonNull</span> <span class="n">MethodCall</span> <span class="n">call</span><span class="o">,</span> <span class="nd">@NonNull</span> <span class="n">MethodChannel</span><span class="o">.</span><span class="na">Result</span> <span class="n">result</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">call</span><span class="o">.</span><span class="na">method</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="s">&#34;flutter_change_language&#34;</span><span class="o">))</span> <span class="o">{</span>
                    <span class="n">String</span> <span class="n">callMsg</span> <span class="o">=</span> <span class="n">call</span><span class="o">.</span><span class="na">arguments</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
                    <span class="c1">// 回调 Flutter 模块那边
</span><span class="c1"></span>                    <span class="n">result</span><span class="o">.</span><span class="na">success</span><span class="o">(</span><span class="n">callMsg</span><span class="o">);</span>
                    <span class="n">mBtnChangeLanguage</span><span class="o">.</span><span class="na">setText</span><span class="o">(</span><span class="n">callMsg</span><span class="o">);</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">});</span>
    <span class="o">}</span>

    <span class="kd">protected</span> <span class="n">FlutterEngine</span> <span class="nf">getFlutterEngine</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">mFlutterFragment</span><span class="o">.</span><span class="na">getFlutterEngine</span><span class="o">();</span>
    <span class="o">}</span>

    <span class="kd">private</span> <span class="n">BinaryMessenger</span> <span class="nf">getBinaryMessenger</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">getFlutterEngine</span><span class="o">()</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="k">return</span> <span class="n">getFlutterEngine</span><span class="o">().</span><span class="na">getDartExecutor</span><span class="o">().</span><span class="na">getBinaryMessenger</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div><h3 id="android-向-flutter-通信">Android 向 Flutter 通信</h3>
<h4 id="android-端-1">Android 端</h4>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">public class FlutterDemoActivity extends AppCompatActivity {

    private static final String TAG_FLUTTER_FRAGMENT = &#34;flutter_fragment&#34;;
    private MaterialButton mBtnChangeLanguage;
    private FlutterFragment mFlutterFragment;

    private MethodChannel mMethodChannel;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activiy_flutter_demo);
        mBtnChangeLanguage = findViewById(R.id.btn_change_language);

        FragmentManager fragmentManager = getSupportFragmentManager();

        mFlutterFragment = (FlutterFragment) fragmentManager.findFragmentByTag(TAG_FLUTTER_FRAGMENT);

        // Create and attach a FlutterFragment if one does not exist.
        if (mFlutterFragment == null) {
            mFlutterFragment = FlutterFragment.withNewEngine()
                    .initialRoute(&#34;Flutter Demo&#34;)
                    .build();

            fragmentManager
                    .beginTransaction()
                    .add(R.id.container, mFlutterFragment, TAG_FLUTTER_FRAGMENT)
                    .commit();
        }
    }

    @Override
    protected void onPostCreate(@Nullable Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // 通道名称需要与 Flutter 模块那边统一，并且唯一
        mMethodChannel = new MethodChannel(getBinaryMessenger(), &#34;com.chicdeals/methodsChannel&#34;);

        mBtnChangeLanguage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String sendMsg = &#34;原生切换语言&#34;;
                // 向 Flutter 模块发送消息，标识符为 &#39;native_change_language&#39;，并带上消息
                mMethodChannel.invokeMethod(&#34;native_change_language&#34;, sendMsg);
                mBtnChangeLanguage.setText(sendMsg);
            }
        });
    }

    protected FlutterEngine getFlutterEngine() {
        return mFlutterFragment.getFlutterEngine();
    }

    private BinaryMessenger getBinaryMessenger() {
        if (getFlutterEngine() == null) {
            return null;
        }

        return getFlutterEngine().getDartExecutor().getBinaryMessenger();
    }
}

</code></pre></div><h4 id="flutter-端-1">Flutter 端</h4>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">class MethodChannelPage extends StatefulWidget {
  @override
  _MethodChannelPageState createState() =&gt; _MethodChannelPageState();
}

class _MethodChannelPageState extends State&lt;MethodChannelPage&gt; {
  // 创建通信渠道，通道名称必须唯一，且与原生那边统一
  MethodChannel methodsChannel = MethodChannel(&#34;com.chicdeals/methodsChannel&#34;);
  String _langText = &#39;切换语言&#39;;

  @override
  Widget build(BuildContext context) {
    return Scaffold (
      backgroundColor: Color(0xFFFFFFFF),
      body: Align(
        alignment: Alignment.center,
        child: Container(
          height: 44,
          padding: EdgeInsets.only(left: 10, right: 10),
          alignment: Alignment.center,
          child: RaisedButton(
            child: Text(
              _langText,
            ),
            textColor: Colors.white,
            color: Color(0xFF49C9A7),
            onPressed: _sendMethodToNative,
          ),
        ),
      ),
    );
  }

  @override
  void initState() {
    // 监听原生传递消息回调
    methodsChannel.setMethodCallHandler(_nativeCallHandler);
    super.initState();
  }

  Future&lt;dynamic&gt; _nativeCallHandler(MethodCall call) async {
    if(call.method == &#39;native_change_language&#39;) {
      // 取出从原生带过来的信息
      String callMsg = call.arguments.toString();
      setState(() {
        _langText = callMsg;
      });
    }
  }
}
</code></pre></div><h3 id="demo-展示">Demo 展示</h3>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2020/04/flutter_channel_02.gif">
<img src="/images/2020/04/flutter_channel_02.gif" alt="image"  />
</a>
</div>

</p>
<h3 id="参考链接">参考链接</h3>
<ul>
<li><a href="https://flutter.cn/docs/development/platform-integration/platform-channels#step-3-add-an-android-platform-specific-implementation">撰写双端平台代码（插件编写实现）</a></li>
<li><a href="https://juejin.im/post/6844903873358856200">一篇看懂 Android 与 Flutter 之间的通信</a></li>
<li><a href="https://segmentfault.com/a/1190000021012102">Flutter混合开发(三)：Android与Flutter之间通信详细指南</a></li>
</ul>
</div>
                    <div class="post_footer">
                        
                        <div class="meta">
                            <div class="info">
                                <span class="field tags">
                                    <i class="ri-stack-line"></i>
                                    
                                    <a href="https://gojun.me/tags/flutter/">Flutter</a>
                                    
                                </span>
                            </div>
                        </div>
                        
                    </div>
                </div>
                
                
                <div class="doc_comments"></div>
                
            </div>
        </div>
    </div>
    <a id="back_to_top" href="#" class="back_to_top"><i class="ri-arrow-up-s-line"></i></a>
    <footer class="footer">
    <div class="footer_slogan">
        <span></span>
    </div>
</footer>
    <script src="https://gojun.me/js/jquery-3.5.1.min.js"></script>
<link href="https://gojun.me/css/fancybox.min.css" rel="stylesheet">
<script src="https://gojun.me/js/fancybox.min.js"></script>
<script src="https://gojun.me/js/zozo.js"></script>


<script type="text/javascript" async
    src="https://cdn.bootcss.com/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
        MathJax.Hub.Config({
            tex2jax: {
                inlineMath: [['$', '$'], ['\\(', '\\)']],
                displayMath: [['$$', '$$'], ['\[\[', '\]\]']],
                processEscapes: true,
                processEnvironments: true,
                skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
                TeX: {
                    equationNumbers: { autoNumber: "AMS" },
                    extensions: ["AMSmath.js", "AMSsymbols.js"]
                }
            }
        });

        MathJax.Hub.Queue(function () {
            
            
            
            var all = MathJax.Hub.getAllJax(), i;
            for (i = 0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

<style>
    code.has-jax {
        font: inherit;
        font-size: 100%;
        background: inherit;
        border: inherit;
        color: #515151;
    }
</style>



<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
	window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
	ga('create', 'UA-142037913-1', 'auto');
	
	ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>

</body>

</html>